package com.zzr.demo.springsecurity.six.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

/**
 * @author: xiaomi
 * @date: 2021/6/22
 * @description:
 */
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    UserDetailsService userDetailsService;

    /**
     * 注入数据源
     */
    @Autowired
    DataSource dataSource;

    /**
     * 自定义登录认证
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //super.configure(auth);
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    /**
     * 配置自定义登录页
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);


        //1. 表单登录
        http.formLogin()    //自定义自己编写的登录页面
                .loginPage("/login.html")   //登录页面设置
                .loginProcessingUrl("/user/login")  //登录访问路径
                .defaultSuccessUrl("/success.html").permitAll()   //登录成功后，跳转路径；允许所有
                .and().authorizeRequests()  //所有请求都能访问
                .antMatchers("/", "test/hello", "/user/login").permitAll()  //多个路径都能访问
                //1. 当前登录用户，只有具有 admins 权限才可以访问这个路径 hasAuthority - 只针对单一权限
                .antMatchers("/test/index").hasAuthority("admins")
                //2. 当前登录用户，只要具有 admins,manager 任一权限就可以访问这个路径 hasAnyAuthority - 可以针对多个权限
                .antMatchers("/test/test").hasAnyAuthority("admins,managers")
                .antMatchers("/test/test2").hasAnyAuthority("testers,managers")
                //3. 当前登录用户，判断是否具有角色 sale
                .antMatchers("/test/testRole").hasRole("sale")
                .antMatchers("/test/testRoleDeveloper").hasRole("developer")
                //4. 当前登录用户，判断是否具有角色集合之一
                .antMatchers("/test/testRole").hasAnyRole("developer,uis")
                .anyRequest().authenticated();


        //- Remember-Me
        //http.rememberMe().tokenRepository(persistentTokenRepository()).tokenValiditySeconds(3600).userDetailsService(userDetailsService);
        http.csrf().disable();    //关闭 csrf 防护


        //2. 配置无权限页
        http.exceptionHandling().accessDeniedPage("/unauth.html");

        //3. 退出登录-在框架里做了 session 失效处理
        http.logout().logoutUrl("/logout").logoutSuccessUrl("/test/hello").permitAll();
    }

    /**
     * 注入 PasswordEncoder  类到 spring  容器中
     * 不然会有异常
     *
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        //第一次启动就会创建表（但是创建之后，这句话就会报错！）
//        jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }
}
